`timescale 1ns / 1ps
//Name: Robert Smith
//PID: A08609119
//Name: Shreenidhi Chowkwale
//PID: A09089080

module dmem#(parameter A_WIDTH = 13, D_WIDTH = 34, INSTR_WIDTH = 136)
  (
    input  reset_i,
    input  clk,
    input  read_write_req_i,
    input  write_en_i,
    input  [A_WIDTH-1 : 0] addr_i,
    input  [D_WIDTH-1 : 0] din_i,
    output [INSTR_WIDTH-1 : 0] dout_o,
    output refused_o
	);
	
	reg  [2:0] counter;
	reg  refused_r;
	reg  read_req_r;
	reg  read_write_req_r;
	wire refused_w;
	reg [INSTR_WIDTH-1 : 0] dout_temp;
	wire write_control;
    reg write_control_a, write_control_b, write_control_c, write_control_d;

	//assign write_control = read_write_req & write_en_i & ~refused_w;
	assign write_control = read_write_req_i & write_en_i;
	assign refused_o = refused_r & read_write_req_r;
	//assign refused_w = counter[2] & counter[1] & counter[0];
	assign refused_w = 0;
	//assign dout = (refused_o | ~read_req_r)? {(D_WIDTH){1'b1}} : dout_temp;
	assign dout_o = (~read_req_r) ? {(D_WIDTH){1'b1}} : dout_temp;

	//assign write_control = read_write_req_i & write_en_i & ~refused_r;
	//assign refused_o = refused_r & read_write_req_r;
	//assign refused_w = counter[2] & counter[1] & counter[0];
	//assign dout_o = (refused_o | ~read_req_r)? {(D_WIDTH){1'b1}} : dout_temp;

	wire [A_WIDTH - 3 : 0] base_addr;
    reg [A_WIDTH - 3 : 0] addr_a, addr_b, addr_c, addr_d;
	reg [D_WIDTH - 1 : 0] rd_data_a, rd_data_b, rd_data_c, rd_data_d;	
	
    assign base_addr = addr_i[A_WIDTH - 1 : 2];
     
    always_comb
        begin
            // Initialize to "normal" values
            addr_a = base_addr;
            addr_b = base_addr;
            addr_c = base_addr;
            addr_d = base_addr;
            dout_temp = {rd_data_a, rd_data_b, rd_data_c, rd_data_d};
            write_control_a = 0;
            write_control_b = 0;
            write_control_c = 0;
            write_control_d = 0;
            // Modify wires as necessary based on lower 2 bits of address
            casez (addr_i[1 : 0])
                2'b00:
                    begin
                        write_control_a = write_control;
                    end
                2'b01:
                    begin
                        write_control_b = write_control;
                        dout_temp = {rd_data_b, rd_data_c, rd_data_d, rd_data_a};
                        addr_a = base_addr + 1;
                    end
                2'b10:
                    begin
                        write_control_c = write_control;
                        dout_temp = {rd_data_c, rd_data_d, rd_data_a, rd_data_b};
                        addr_a = base_addr + 1;
                        addr_b = base_addr + 1;
                    end
                2'b11:
                    begin
                        write_control_d = write_control;
                        dout_temp = {rd_data_d, rd_data_a, rd_data_b, rd_data_c};
                        addr_a = base_addr + 1;
                        addr_b = base_addr + 1;
                        addr_c = base_addr + 1;
                    end
            endcase
        end
                            
                    
	dmem_34_2048_1port dmem_a
	(
		.address(addr_a)
		,.clock(clk)
		,.data(din_i)
		,.wren(write_control_a)
		,.q(rd_data_a)
	);
	
	dmem_34_2048_1port dmem_b
	(
		.address(addr_b)
		,.clock(clk)
		,.data(din_i)
		,.wren(write_control_b)
		,.q(rd_data_b)
	);
	
	dmem_34_2048_1port dmem_c
	(
		.address(addr_c)
		,.clock(clk)
		,.data(din_i)
		,.wren(write_control_c)
		,.q(rd_data_c)
	);
	
	dmem_34_2048_1port dmem_d
	(
		.address(addr_d)
		,.clock(clk)
		,.data(din_i)
		,.wren(write_control_d)
		,.q(rd_data_d)
	);
	
	always_ff @(posedge clk)
		begin
			if (reset_i)
				counter <= 3'b0;
			else
				counter <= counter + 1;

			refused_r <= refused_w;
			read_write_req_r <= read_write_req_i;
			read_req_r <= read_write_req_i & ~write_en_i;
		end
	
endmodule
